#include "utils.hpp"

int Ponto::indiceCont = 0;

Ponto::Ponto(int dim, int indice){
    this->dim = dim;
    this->indice = indice;
    this->coordenadas = (float*) calloc(dim, sizeof(float));
}

Ponto::Ponto(int dim){
	if(dim>0) {
		this->dim = dim;
		this->indice = Ponto::indiceCont++;
		this->coordenadas = (float*) calloc(dim, sizeof(float));
	}
	else{
		this->dim = 0;
		this->indice = -1;
		this->coordenadas = NULL;
	}
}

Ponto::~Ponto(){
	if(this->coordenadas) free(this->coordenadas);
}

int Ponto::getDim(){
	return this->dim;
}

int Ponto::getIndice(){

	return this->indice;
}

void Ponto::setCoord(int indiceEixo, float valor){
	if(0<indiceEixo&&indiceEixo<this->dim) this->coordenadas[indiceEixo] = valor;
}

float Ponto::getCoord(int indiceEixo){
    if (this == NULL) return 0.0;///<<<modifiquei aqui pq ta vindo null e dá pau
    if(0<=indiceEixo&&indiceEixo<this->dim) return this->coordenadas[indiceEixo];
	return 0.0;
}

void Ponto::print(){
    int i;
    printf("\n%d: ", this->indice);
    for(i = 0; i < this->dim; i++)
        printf("%.2f ", this->coordenadas[i]);
    printf("\n");
}

void Ponto::gera(){
    int i;
    for(i = 0; i < this->dim; i++)
        this->coordenadas[i] = rand() % 10;
}

void Ponto::float2ponto(float p[], int tam){
    if(tam==this->dim){
        for(int i = 0; i < tam; i++){
            this->coordenadas[i] = p[i];
        }
    }
}

void Ponto::copia(Ponto **destino){
    if(*destino) delete *destino;

	*destino = new Ponto(this->dim, this->indice);

	for(int i = 0; i < this->dim; i++) (*destino)->coordenadas[i] = this->coordenadas[i];
}

BoundingBox::BoundingBox(int dim){
	if(dim>0){
		this->dim = dim;
		this->eixoMax = (float*) calloc(dim,sizeof(float));
		this->eixoMin = (float*) calloc(dim,sizeof(float));
	}
	else{
		this->dim = 0;
		this->eixoMax = NULL;
		this->eixoMin = NULL;
	}
}

BoundingBox::~BoundingBox(){
	if(this->eixoMax) free(this->eixoMax);
	if(this->eixoMin) free(this->eixoMin);
}

int BoundingBox::getDim(){
    return this->dim;
}

void BoundingBox::setEixoMin(int indiceEixo, float valor){
    if(0<=indiceEixo&&indiceEixo<this->dim) this->eixoMin[indiceEixo] = valor;
}

void BoundingBox::setEixoMax(int indiceEixo, float valor){
    if(0<=indiceEixo&&indiceEixo<this->dim) this->eixoMax[indiceEixo] = valor;
}

float BoundingBox::getEixoMin(int indiceEixo){
    if(0<=indiceEixo&&indiceEixo<this->dim) return this->eixoMin[indiceEixo];
    return 0.0;
}

float BoundingBox::getEixoMax(int indiceEixo){
    if(0<=indiceEixo&&indiceEixo<this->dim) return this->eixoMax[indiceEixo];
    return 0.0;
}

void BoundingBox::copia(BoundingBox *destino){
	if(destino) delete destino;
	destino = new BoundingBox(this->dim);

	int i;
	for(i = 0; i < this->dim; i++){
		destino->eixoMax[i] = this->eixoMax[i];
		destino->eixoMin[i] = this->eixoMin[i];
	}
}

void BoundingBox::insere(Ponto *ponto){
	int i;

	for(i = 0; i < this->dim; i++){
        this->eixoMax[i] = MAIOR(this->eixoMax[i], ponto->getCoord(i));
        this->eixoMin[i] = MENOR(this->eixoMin[i], ponto->getCoord(i));
	}
}

float BoundingBox::area(){
	int i;
	float area = 1.0;

	for(i = 0; i < this->dim; i++)
		area*= this->eixoMax[i] - this->eixoMin[i];
	return area;
}

float BoundingBox::sobreposicao(BoundingBox *bb){
	int i;
	float area = 1.0, a, b;

	if(this->dim!=bb->dim) return 0.0;

	for(i = 0; i < this->dim; i++){
        a = MENOR(this->eixoMax[i], bb->eixoMax[i]);
        b = MAIOR(this->eixoMin[i], bb->eixoMin[i]);
        if (b>a) area*= b-a;
        else return 0.0;
	}

	return area;
}

void BoundingBox::ajustaFolha(EntradaFolha **ent, int tamanho){
    int i, j;

    for(i = 0; i < this->dim; i++){
        this->eixoMin[i] = INFINITY;
        this->eixoMax[i] = -INFINITY;
        for(j = 0; j < tamanho; j++){
            this->eixoMin[i] = MENOR(this->eixoMin[i], ent[j]->p->getCoord(i));
            this->eixoMax[i] = MAIOR(this->eixoMax[i], ent[j]->p->getCoord(i));
        }
    }
}

void BoundingBox::ajustaInterna(EntradaInterna **ent, int tamanho){
	int i, j;

	for(i = 0; i < this->dim; i++){
		this->eixoMin[i] = INFINITY;
        this->eixoMax[i] = -INFINITY;
        for(j = 0; j < tamanho; j++){
            if (ent[j] != NULL){
                if (ent[j]->bb != NULL){
                    this->eixoMin[i] = MENOR(this->eixoMin[i], ent[j]->bb->getEixoMin(i));
                    this->eixoMax[i] = MAIOR(this->eixoMax[i], ent[j]->bb->getEixoMax(i));
                }
            }
        }
	}
}

void BoundingBox::print(){
    int i;
    printf("\n");
    for(i = 0; i < this->dim; i++)
        printf("(%.2f %.2f) ", this->eixoMin[i], this->eixoMax[i]);
    printf("\n");
}

void ordenacao(float vetor[], int pos[], int tamanho){
    int i,j, auxI;
    float aux;

    for(i = 0; i < tamanho; i++) pos[i] = i;

    for(i = 0; i < tamanho-1; i++){
        for(j = i+1; j < tamanho; j++){
            if(vetor[i] > vetor[j]){
                aux = vetor[i];
                vetor[i] = vetor[j];
                vetor[j] = aux;

                auxI = pos[i];
                pos[i] = pos[j];
                pos[j] = auxI;
            }
        }
    }
}

void kMaiores(float vetor[], int tamanho, int k, int maiores[]){
    int i, j, auxI, pos[tamanho];
    float aux;

    for(i = 0; i < tamanho; i++) pos[i] = i;

    for(i = 0; i < k; i++){
        for(j = i+1; j < tamanho; j++)
            if(vetor[i] < vetor[j]){
                aux = vetor[i];
                vetor[i] = vetor[j];
                vetor[j] = aux;

                auxI = pos[i];
                pos[i] = pos[j];
                pos[j] = auxI;
            }
        maiores[i] = pos[i];
    }
}
